package com.jl.card.provider.jl3g;

import opencard.opt.util.TLV;
import opencard.opt.util.Tag;

import com.jl.card.file.IFileInfo;
import com.jl.card.filesystem.EFarr;
import com.jl.card.filesystem.IEF;
import com.jl.util.HexUtil;

public class JL3GFileInfo implements IFileInfo {

	private EFarr efarr = null;

	private static final Tag tagFCP_FILE_SIZE = new Tag(0x00, (byte) 2, false);
	private static final Tag tagFCP_TOTAL_FILE_SIZE = new Tag(0x01, (byte) 2,
			false);
	private static final Tag tagFCP_FILE_TYPE = new Tag(0x02, (byte) 2, false);
	private static final Tag tagFCP_FID = new Tag(0x03, (byte) 2, false);
	private static final Tag tagFCP_SECURITY = new Tag(0x0B, (byte) 2, false);

	byte[] fci = null;
	int filelength = -1;
	short fileid = -1;
	int filetype = 8;
	int recordsize = -1;

	private int refEFarrNum = -1;
	private short refEFarrID = -1;

	/**
	 * 
	 */
	public JL3GFileInfo() {
	}

	/**
	 * Create file control information from TLV coded byte array
	 * 
	 * @param newfci
	 *            File control information obtained from the card
	 */
	public JL3GFileInfo(byte[] newfci) {
		fci = newfci;
		TLV fcp, cursor;

		try {
			fcp = new TLV(fci);
			cursor = null;
			while ((cursor = fcp.findTag(null, cursor)) != null) {
				if (cursor.tag().isConstructed()) {
					// Ignore constructed elements in FCP
				} else if (cursor.tag().equals(tagFCP_FILE_SIZE)) {
					filelength = cursor.valueAsNumber();
				} else if (cursor.tag().equals(tagFCP_FILE_TYPE)) {
					byte tb[] = cursor.valueAsByteArray();

					filetype = tb[0] & 0x07;//
					if (tb.length >= 3) {
						recordsize = tb[2];
					}
					if (tb.length >= 4) {
						recordsize = (recordsize << 8) + tb[3];
					}
				} else if (cursor.tag().equals(tagFCP_TOTAL_FILE_SIZE)) {
					if (filelength == -1)
						filelength = cursor.valueAsNumber();
				} else if (cursor.tag().equals(tagFCP_FID)) {
					fileid = (short) cursor.valueAsNumber();
				} else if (cursor.tag().equals(tagFCP_SECURITY)) {
					byte tb[] = cursor.valueAsByteArray();
					this.refEFarrID = HexUtil.makeShort(tb, 0);
					if (tb.length == 3) {
						refEFarrNum = tb[2] & 0xFF;
					} else {
						refEFarrNum = tb[tb.length - 1] & 0xFF;
					}
				}
			}
		} catch (Exception e) {
			// Silently ignore problems decoding TLV structure
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see opencard.opt.iso.fs.CardFileInfo#getFileID()
	 */
	@Override
	public short getFileID() {
		return fileid;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see opencard.opt.iso.fs.CardFileInfo#isDirectory()
	 */
	@Override
	public boolean isDirectory() {
		return filetype == 0;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see opencard.opt.iso.fs.CardFileInfo#isTransparent()
	 */
	@Override
	public boolean isTransparent() {
		return filetype == 1;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see opencard.opt.iso.fs.CardFileInfo#isCyclic()
	 */
	@Override
	public boolean isCyclic() {
		return (filetype & 6) == 6;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see opencard.opt.iso.fs.CardFileInfo#isVariable()
	 */
	@Override
	public boolean isVariable() {
		// not sure
		return (filetype & 6) == 4;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see opencard.opt.iso.fs.CardFileInfo#getLength()
	 */
	@Override
	public int getLength() {
		return filelength;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see opencard.opt.iso.fs.CardFileInfo#getRecordSize()
	 */
	@Override
	public int getRecordSize() {
		return recordsize;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see opencard.opt.iso.fs.CardFileInfo#getHeader()
	 */
	@Override
	public byte[] getHeader() {
		return fci;
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("File ID      : ").append(HexUtil.toHex(fileid, 2))
				.append('\n');
		if (!isDirectory()) {
			sb.append("File Size    : ").append(filelength + "").append('\n');
		}

		//
		String fileType = null;
		if (getFileID() == 0x3F00) {
			fileType = "MF";
		} else if (isDirectory()) {
			fileType = "DF";
		} else {
			fileType = "EF";
		}
		//
		String fileStruct = null;
		if (isTransparent()) {
			fileStruct = "Transparent";
		} else if (isCyclic()) {
			fileStruct = "Cyclic";
		} else {
			fileStruct = "Linear fixed";
		}

		sb.append("File Type    : ").append(fileType);
		if (!isDirectory()) {
			sb.append('(').append(fileStruct).append(')').append('\n');
		}

		if (!isDirectory() && !isTransparent()) {
			sb.append("Record Size  : ").append(recordsize + "").append('\n');
			sb.append("Record Num   : ").append(filelength / recordsize + "")
					.append('\n');
		}

		sb.append("Security     : ").append("EFarr(")
				.append(HexUtil.toHex(refEFarrID & 0xFFFF, 2))
				.append(") record ").append("" + this.refEFarrNum).append('\n');
		sb.append(efarr.parseRecord(this.refEFarrNum).get(
				isDirectory() ? EFarr.TYPE_DF : EFarr.TYPE_EF));
		return sb.toString().trim();

	}

	public void setEFarr(IEF ef) {
		efarr = (EFarr) ef;
	}

	public short getEFarrID() {
		return refEFarrID;
	}
}
